# audio_player.py
import pyaudio
import threading
import queue
from typing import Optional

_DEFAULTS = dict(
    format=pyaudio.paInt16,
    channels=2,
    rate=44100,
    chunk=1024,
)


class _AudioPlayer:
    def __init__(self, **kw):
        # 用外界传入或缺省值
        self.format = kw.get('format', _DEFAULTS['format'])
        self.channels = kw.get('channels', _DEFAULTS['channels'])
        self.rate = kw.get('rate', _DEFAULTS['rate'])
        self.chunk = kw.get('chunk', _DEFAULTS['chunk'])

        self._pa = pyaudio.PyAudio()
        self._stream = None
        self._q = queue.Queue()
        self._played = threading.Event()
        self._total_feed = 0
        self._total_played = 0
        self._lock = threading.Lock()
        self._thread = threading.Thread(target=self._worker, daemon=True)
        self._thread.start()

    # ---- 内部工作线程 ----
    def _worker(self):
        while True:
            data = self._q.get()
            if data is None:
                break
            if self._stream is None:
                self._stream = self._pa.open(
                    format=self.format,
                    channels=self.channels,
                    rate=self.rate,
                    output=True,
                    frames_per_buffer=self.chunk
                )
            self._stream.write(data)
            with self._lock:
                self._total_played += len(data)
                if self._total_played >= self._total_feed:
                    self._played.set()

    # ---- 对外接口 ----
    def feed(self, data: bytes):
        if not isinstance(data, bytes):
            raise TypeError("feed() 需要 bytes")
        with self._lock:
            self._total_feed += len(data)
            self._played.clear()
        self._q.put(data)

    def wait(self):
        self._played.wait()

    def clear(self):
        """清空待播放队列并重置相关状态"""
        with self._lock:
            # 清空队列
            while not self._q.empty():
                try:
                    self._q.get_nowait()
                except queue.Empty:
                    break

            # 重置计数状态
            unplayed = self._total_feed - self._total_played
            self._total_feed = self._total_played  # 剩余未播放的都被清空了
            if self._total_played >= self._total_feed:
                self._played.set()

    # ---- 清理 ----
    def close(self):
        self._q.put(None)
        self._thread.join(timeout=1)
        if self._stream:
            self._stream.close()
        self._pa.terminate()


# 模块级变量
_player: Optional[_AudioPlayer] = None


def init(**kw):
    """一次性初始化播放器（必须在首次使用前调用）"""
    global _player
    if _player is not None:
        raise RuntimeError("player 已经初始化过了")
    _player = _AudioPlayer(**kw)


def feed(data: bytes):
    if _player is None:
        raise RuntimeError("请先调用 audio_player.init(...)")
    _player.feed(data)


def wait():
    if _player is None:
        raise RuntimeError("请先调用 audio_player.init(...)")
    _player.wait()


def clear():
    """清空待播放的所有数据"""
    if _player is None:
        raise RuntimeError("请先调用 audio_player.init(...)")
    _player.clear()


def close():
    global _player
    if _player is not None:
        _player.close()
        _player = None
